package coop.bancocredicoop.proyectos.gd.reports;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.classic.Session;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.type.Type;

import coop.bancocredicoop.proyectos.gd.domain.Document;

public class CountByReport {

	private Criteria countByCriteria(Criteria criteria, Long idPersona, String cajaId, Date dateFrom, Date dateTo) {	
		
		criteria = criteria.add(Restrictions.isNull("deleteDate"));
		if (idPersona != null) {
			criteria = criteria.createAlias("customer", "asociado")
				.add(Restrictions.eq("asociado.idPersona", idPersona));
		}
			
		if (cajaId != null) {
			criteria = criteria.createAlias("box", "box")
				.add(Restrictions.eq("box.cajaId", cajaId));
		}
		
		if (dateFrom != null) {
			criteria = criteria.add(Restrictions.gt("createdDate", dateFrom));
		}
		
		if (dateTo != null) {
			criteria = criteria.add(Restrictions.le("createdDate", dateTo));
		}
		return criteria;
	}

	private QueryResult countByProperty(Session session, String propertyName, Long idPersona, String cajaId, Date dateFrom, Date dateTo, Integer offset, Integer max) {
		
		return countByProperty(session, propertyName, Projections.groupProperty(propertyName), idPersona, cajaId, dateFrom, dateTo, offset, max);
	    
	}
	
	private QueryResult countByProperty(Session session, String propertyName, Projection groupByProjection, Long idPersona, String cajaId, Date dateFrom, Date dateTo, Integer offset, Integer max) {
		
	    Criteria criteria = session.createCriteria(Document.class);
	    criteria = countByCriteria(criteria, idPersona, cajaId, dateFrom, dateTo);
	    criteria = criteria.setMaxResults(max)
	    	.setFirstResult(offset)
	    	.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
	       	.setProjection(Projections.projectionList()
	       			.add(groupByProjection)
	       			.add(Projections.count(propertyName).as("amount")))
		    .addOrder(Order.desc("amount"));
	    
	    Criteria countCriteria = session.createCriteria(Document.class);
	    countCriteria.setProjection(Projections.projectionList()
	    	.add(Projections.distinct(Projections.count(propertyName))));
	    
	    countCriteria = countByCriteria(countCriteria, idPersona, cajaId, dateFrom, dateTo);

	    Integer totalItems = (Integer) countCriteria.list().get(0);
	    List<Object[]> rows = criteria.list();
	    List<Map<String, Object>> result = new ArrayList<Map<String,Object>>();
	    
	    for (Object[] row : rows) {
	    	Map<String, Object> item = new HashMap<String, Object>();
	    	item.put(propertyName, row[0]);
	    	item.put("amount", row[1]);
	    	result.add(item);
	    }
	    
	    return new QueryResult(result, totalItems, offset);
	    
	}
	
	public QueryResult countByCustomer(Session session, Long idPersona, String cajaId, Date dateFrom, Date dateTo, Integer offset, Integer limit) {
		return countByProperty(session, "customer", idPersona, cajaId, dateFrom, dateTo, offset, limit);
	}
	
	public QueryResult countByBox(Session session, Long idPersona, String cajaId, Date dateFrom, Date dateTo, Integer offset, Integer limit) {
		return countByProperty(session, "box", idPersona, cajaId, dateFrom, dateTo, offset, limit);
	}
	
	public QueryResult countByDate(Session session, Long idPersona, String cajaId, Date dateFrom, Date dateTo, Integer offset, Integer limit) {
		Projection dateProjection = Projections.sqlGroupProjection("date(created_date) as createdDate", "createdDate", new String[] { "createdDate" }, new Type[] { new org.hibernate.type.DateType() } );
		return countByProperty(session, "createdDate", dateProjection, idPersona, cajaId, dateFrom, dateTo, offset, limit);
	}
	
}
